home *** CD-ROM | disk | FTP | other *** search
/ Maclife 157 / MACLIFE157-2001-09.ISO.7z / MACLIFE157-2001-09.ISO / Linux / MacOS Tools / Other / BootX 1.1.3 (for Old Mac OS) / Sources / lib / MoreOSUtils / MoreOSUtils.c next >
Text File  |  2001-07-23  |  11KB  |  371 lines

  1. /*
  2.     File:        MoreOSUtils.c
  3.  
  4.     Contains:    A OS utility library.
  5.  
  6.     Written by:    Quinn
  7.  
  8.     Copyright:    Copyright ゥ 1998 by Apple Computer, Inc., all rights reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.  
  20.          <2>     16/3/99    Quinn   Rolled in InterfaceDisableLib from DTS Technote 1137.
  21.          <1>      1/3/99    Quinn   First checked in.
  22. */
  23.  
  24. /////////////////////////////////////////////////////////////////////
  25.  
  26. // MoreIsBetter Setup
  27.  
  28. #include "MoreSetup.h"
  29.  
  30. // Mac OS interfaces
  31.  
  32. #include <Traps.h>
  33. #include <Gestalt.h>
  34. #include <CodeFragments.h>
  35. #include <MixedMode.h>
  36.  
  37. // MIB Prototypes
  38.  
  39. #include "MoreInterfaceLib.h"
  40.  
  41. // Our Prototypes
  42.  
  43. #include "MoreOSUtils.h"
  44.  
  45. /////////////////////////////////////////////////////////////////////
  46.  
  47. // We require Universal Interfaces 3.2 because earlier versions
  48. // either mess up the prototype for FlushCodeCacheRange, or don't
  49. // define it for CFM code, or both!
  50.  
  51. #if UNIVERSAL_INTERFACES_VERSION < 0x0320
  52.     #error MoreOSUtils.c requires Universal Interfaces 3.2 or higher.
  53. #endif
  54.  
  55. /////////////////////////////////////////////////////////////////////
  56. #pragma mark ----- 68K Code Cache Flush -----
  57.  
  58. // Define the _vCacheFlush trap (used by FlushCodeCache), which is not included
  59. // in Universal Interfaces.
  60.  
  61. enum {
  62.     _vCacheFlush = 0xA0BD
  63. };
  64.  
  65. #if TARGET_CPU_68K
  66.  
  67.     // The following routines are used to flush the cache using direct
  68.     // 680x0 instructions.  They are only used if no OS support is available.
  69.     //
  70.     // Because these routines take no parameters and return no results,
  71.     // they are equally effective for both classic 68K and CFM-68K.
  72.     
  73.     static void FlushCacheViaCACR(void) =
  74.         // FlushCacheViaCACR is an inline assembly routine that flushes both the 
  75.         // instruction and data caches by writing directly to the CACR.  Used
  76.         // as a last resort by MakeData68KExecutable on 68020 and 68030.
  77.     {
  78.         0x4E7A, 0x0002,        // MOVEC    CACR,D0
  79.         0x08C0, 0x0003,        // BSET        #3,D0
  80.         0x4E7B, 0x0002        // MOVEC    D0,CACR
  81.      };
  82.  
  83.     static void FlushCacheWithCPushA(void) =
  84.         // FlushCacheWithCPushA is another inline assembly routine that flushes caches
  85.         // on the MC68040 using the CPushA instruction.  Used as a last resort
  86.         // by MakeData68KExecutable on 68040.
  87.     {
  88.         0x4E71,                // NOP                ; to clear pending writes
  89.          0xF4F8                // CPUSHA    BC
  90.     };
  91.  
  92. #endif
  93.  
  94. extern pascal OSStatus MakeData68KExecutable(void *address, ByteCount count)
  95.     // See comment in interface part.
  96. {
  97.     OSErr err;
  98.  
  99.     #if TARGET_CPU_PPC
  100.         MoreAssertQ(GetOSTrapAddress(_HWPriv) != GetToolTrapAddress(_Unimplemented));
  101.     #endif
  102.     
  103.     // Step 1.  If we have _HWPriv, try calling FlushCodeCacheRange.  If that
  104.     // returns an error, call FlushCodeCache.  Two important assumptions:
  105.     //
  106.     // a) any machine that has FlushCodeCacheRange implemented will necessarily
  107.     //    implement FlushCodeCache.
  108.     // b) PowerPC computers always have FlushCodeCacheRange implemented, so
  109.     //    we don't need Mixed Mode glue for FlushCodeCache because we'll never
  110.     //    need it on a PowerPC.
  111.     
  112.     if ( GetOSTrapAddress(_HWPriv) != GetToolTrapAddress(_Unimplemented) ) {
  113.         err = MoreFlushCodeCacheRange(address, count);
  114.         #if TARGET_CPU_68K
  115.             if (err != noErr) {
  116.                 MoreAssertQ(GetOSTrapAddress(_vCacheFlush) != GetToolTrapAddress(_Unimplemented));
  117.                 FlushCodeCache();
  118.             }
  119.         #else
  120.             MoreAssertQ(err == noErr);
  121.         #endif
  122.  
  123.     // Step 2.  If we don't have _HWPriv, look to see whether _vCacheFlush
  124.     // (ie FlushCodeCache) is implemented.  If it is, we'll just call it.
  125.     
  126.     } else if ( GetOSTrapAddress(_vCacheFlush) != GetToolTrapAddress(_Unimplemented) ) {
  127.     
  128.         // The call to FlushCodeCache is conditionalised because 
  129.         // Universal Interfaces does not export the call unless
  130.         // you're generating 68K code.  *sigh*  But that's OK because
  131.         // all PowerPC machines have _HWPriv implemented, so this
  132.         // code won't run.
  133.         
  134.         #if TARGET_CPU_68K
  135.             FlushCodeCache();
  136.         #else
  137.             MoreAssertQ(false);
  138.         #endif
  139.         
  140.     // Step 3.  Finally, if neither of these traps is implemented, we're just
  141.     // going to execute 680x0 instructions directly.  Note that we have to
  142.     // execute different instructions based on the 680x0 variant.
  143.     
  144.     } else {
  145.     
  146.         // Obviously, this is only going to work (or indeed compile) if we're
  147.         // generating 68K code.  That's cool, because if we're generating PowerPC
  148.         // code, we must end up running on a PowerPC, and that always has
  149.         // FlushCodeCacheRange so we never get here.
  150.  
  151.         #if TARGET_CPU_68K
  152.             {
  153.                 UInt32 gestaltResponse;
  154.             
  155.                 if (Gestalt(gestaltProcessorType, (SInt32 *) &gestaltResponse) == noErr) {
  156.                     if (gestaltResponse >= gestalt68020) {
  157.                         if (gestaltResponse <= gestalt68030) {
  158.                             FlushCacheViaCACR();
  159.                         } else {
  160.                             FlushCacheWithCPushA();
  161.                         }
  162.                     }
  163.                 }
  164.             }
  165.         #else
  166.             MoreAssertQ(false);
  167.         #endif
  168.     }
  169.     
  170.     // Basically this routine can't fail or, more accurately,
  171.     // there are no expected failure cases.  So we always return
  172.     // noErr.  In fact, the only reason this routine is defined to
  173.     // return an error code is for symmetry with MakeDataPowerPCExecutable,
  174.     // which has to return an error code in the classic 68K case.
  175.     
  176.     return noErr;
  177. }
  178.  
  179. /////////////////////////////////////////////////////////////////////
  180. #pragma mark ----- PowerPC Code Cache Flush -----
  181.  
  182. #if TARGET_CPU_68K && !TARGET_RT_MAC_CFM
  183.  
  184.     // This chunk of code implements the classic 68K case for MakeDataPowerPCExecutable,
  185.     // ie we're running classic 68K code that's generating PowerPC instructions.  Boy,
  186.     // is this a pain to implement.  We have to connect up to Interface, find the
  187.     // appropriate symbol, build a routine descriptor for it, and then call it.
  188.     
  189.     enum {
  190.         uppMakeDataExecutableProcInfo = kPascalStackBased |
  191.                 STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(void *))) |
  192.                 STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(unsigned long)))
  193.     };
  194.  
  195.     static CFragConnectionID gInterfaceLib = nil;
  196.     static UniversalProcPtr  gMakeDataExecutable = nil;
  197.     
  198.     typedef pascal void (*MakeDataExecutableProcPtr)(void *address, unsigned long count);
  199.     
  200.     static pascal OSStatus MakeDataPowerPCExecutableFromClassic(void *address, ByteCount count)
  201.     {
  202.         OSErr err;
  203.         Ptr junkMain;
  204.         Str255 junkMessage;
  205.         CFragSymbolClass junkClass;
  206.         ProcPtr routinePtr;
  207.         
  208.         MoreAssertQ(GetToolTrapAddress(_CodeFragmentDispatch) != GetToolTrapAddress(_Unimplemented));
  209.         MoreAssertQ(GetToolTrapAddress(_MixedModeDispatch)    != GetToolTrapAddress(_Unimplemented));
  210.         
  211.         err = noErr;
  212.         if (gMakeDataExecutable == nil) {
  213.         
  214.             // We're not connected to InterfaceLib let, let's connect, find the MakeDataExecutable
  215.             // symbol, and build a routine descriptor for it.
  216.             
  217.             err = GetSharedLibrary("¥pInterfaceLib", kPowerPCCFragArch, kLoadCFrag, &gInterfaceLib, &junkMain, junkMessage);
  218.             if (err == noErr) {
  219.                 err = FindSymbol(gInterfaceLib, "¥pMakeDataExecutable", (Ptr *) &routinePtr, &junkClass);
  220.             }
  221.             if (err == noErr) {
  222.                 MoreAssertQ(junkClass == kTVectorCFragSymbol);
  223.                 gMakeDataExecutable = NewRoutineDescriptorTrap(routinePtr, uppMakeDataExecutableProcInfo, kPowerPCISA);
  224.                 if (gMakeDataExecutable == nil) {
  225.                     err = memFullErr;
  226.                 }
  227.             }
  228.             
  229.             // If any of this failed, let's shut it all down gracefully.
  230.             
  231.             if (err != noErr) {
  232.                 TermMoreOSUtils();
  233.             }
  234.         }
  235.         
  236.         // If we have a UPP for MakeDataExecutable, call it.
  237.  
  238.         if (gMakeDataExecutable != nil) {    
  239.             ((MakeDataExecutableProcPtr) gMakeDataExecutable)(address, count);
  240.         }
  241.         return err;
  242.     }
  243.     
  244.     extern pascal void TermMoreOSUtils(void)
  245.         // See comment in interface part.
  246.     {
  247.         OSErr junk;
  248.         
  249.         if ( gMakeDataExecutable != nil ) {
  250.             DisposeRoutineDescriptorTrap(gMakeDataExecutable);
  251.             gMakeDataExecutable = nil;
  252.         }
  253.         if ( gInterfaceLib != nil ) {
  254.             junk = CloseConnection(&gInterfaceLib);
  255.             MoreAssertQ(junk == noErr);
  256.             gInterfaceLib = nil;
  257.         }
  258.     }
  259.     
  260. #endif
  261.  
  262. extern pascal OSStatus MakeDataPowerPCExecutable(void *address, ByteCount count)
  263.     // See comment in interface part.
  264. {
  265.     // Note: We don't have to worry about the CFM-68K case because
  266.     // CFM-68K won't run on PowerPC machines, so there's no sense
  267.     // in trying to make some data PowerPC-executable from CFM-68K code.
  268.  
  269.     #if TARGET_RT_MAC_CFM
  270.         #if TARGET_CPU_68K
  271.             #pragma unused(address)
  272.             #pragma unused(count)
  273.             MoreAssertQ(false);
  274.             return noErr;
  275.         #else
  276.             MakeDataExecutable(address, count);
  277.             return noErr;
  278.         #endif
  279.     #else
  280.         return MakeDataPowerPCExecutableFromClassic(address, count);
  281.     #endif
  282. }
  283.  
  284. /////////////////////////////////////////////////////////////////////
  285. #pragma mark ----- Interrupt Enable and Disable -----
  286.  
  287. #if GENERATINGPOWERPC
  288.  
  289.     // PowerPC Specific Code
  290.     
  291.     // On PPC, we use MixedMode to handle moving the PPC parameters
  292.     // into the right 68K registers and back again.  This make our
  293.     // 68K very easy to write.
  294.     
  295.     enum {
  296.         kGetSRProcInfo = kRegisterBased
  297.                 | RESULT_SIZE(SIZE_CODE(sizeof(UInt16)))
  298.                 | REGISTER_RESULT_LOCATION(kRegisterD0),
  299.         kSetSRProcInfo = kRegisterBased
  300.                 | RESULT_SIZE(0)
  301.                 | REGISTER_ROUTINE_PARAMETER(1, kRegisterD0, SIZE_CODE(sizeof(UInt16)))
  302.     };
  303.     
  304.     // We define the 68K as a statically initialised data structure.
  305.     // The use of MixedMode to call these routines makes the routines
  306.     // themselves very simple.
  307.  
  308.     static UInt16 gGetSR[] = {
  309.         0x40c0,        // move sr,d0
  310.         0x4e75        // rts
  311.     };
  312.  
  313.     static UInt16 gSetSR[] = {
  314.         0x46c0,        // move d0,sr
  315.         0x4e75        // rts
  316.     };
  317.  
  318.     static UInt16 GetSR(void)
  319.         // Returns the current value of the SR, interrupt mask
  320.         // and all!  This routine uses MixedMode to call the gGetSR data
  321.         // structure as if it was 68K code (which it is!).
  322.         
  323.     {
  324.         return CallUniversalProc( (UniversalProcPtr) &gGetSR, kGetSRProcInfo);
  325.     }
  326.  
  327.     static void SetSR(UInt16 newSR)
  328.         // Returns the value of the SR, including the interrupt mask and all
  329.         // the flag bits.  This routine uses MixedMode to call the gGetSR data
  330.         // structure as if it was 68K code (which it is!).
  331.     {
  332.         CallUniversalProc( (UniversalProcPtr) &gSetSR, kSetSRProcInfo, newSR);
  333.     }
  334.  
  335. #else
  336.  
  337.     // Classic 68K and CFM-68K Specific Code
  338.  
  339.     // On classic 68K (and CFM-68K) we can simply access the
  340.     // 68K SR register using some inline procedures.
  341.     
  342.     static UInt16 GetSR(void) = {
  343.         0x40c0        // move sr,d0
  344.     };
  345.  
  346.     #pragma parameter SetSR(__D0)
  347.     static void SetSR(UInt16 newSR) = {
  348.         0x46c0        // move d0,sr
  349.     };
  350.  
  351. #endif
  352.  
  353. extern pascal UInt16 GetInterruptMask(void)
  354.     // See comment in header file.
  355. {
  356.     return (GetSR() >> 8) & 7;
  357. }
  358.  
  359. extern pascal UInt16 SetInterruptMask(UInt16 newMask)
  360.     // See comment in header file.
  361. {
  362.     UInt16 currentSR;
  363.  
  364.     MoreAssertQ(newMask >= 0 && newMask <= 7);
  365.         
  366.     currentSR = GetSR();
  367.     SetSR( (currentSR & 0xF8FF) | (newMask << 8) );
  368.     
  369.     return (currentSR >> 8) & 7;
  370. }
  371.